#pragma once

#include "my_defs.h"
#include "my_rwlock.h"
#include "my_spinlock.h"

#define MY_MAX_LOG_SIZE             2048
#define MY_LOG_MIN_ROLLING_SEC      300     // 5 min

typedef enum {
    LOG_LEVEL_DEBUG = 1,
    LOG_LEVEL_WARN  = 2,
    LOG_LEVEL_ERROR = 3,
    LOG_LEVEL_FATAL = 4
} my_log_level_t;

typedef struct {
    my_log_level_t                  level;
    const char                      *log_file;
    int                             fd;
    my_spinlock_t                   single;
    my_rwlock_t                     rwlock;
    int64_t                         rolling_sec;
    int64_t                         last_rolling;   // unix second
} my_log_t;

extern my_log_t                     g_log;

void my_log_init(my_log_level_t level, const char *log_file, int64_t rolling_sec);

void my_log_output(const char *level_str, const char *file,
    int line, my_bool_t abort_proc, const char *fmt, ...);

#define MY_LOG_DEBUG(fmt, args...)                  \
    if (LOG_LEVEL_DEBUG >= g_log.level) my_log_output("debug", __FILE__, __LINE__, 0, fmt, ##args)

#define MY_LOG_WARN(fmt, args...)                  \
    if (LOG_LEVEL_WARN >= g_log.level) my_log_output("warn", __FILE__, __LINE__, 0, fmt, ##args)

#define MY_LOG_ERROR(fmt, args...)                  \
    if (LOG_LEVEL_ERROR >= g_log.level) my_log_output("error", __FILE__, __LINE__, 0, fmt, ##args)

#define MY_LOG_FATAL(fmt, args...)                  \
    if (LOG_LEVEL_FATAL >= g_log.level) my_log_output("fatal", __FILE__, __LINE__, 1, fmt, ##args)
